/*
 * Copyright (C) 2011 Kamran Zafar
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
 * of the Software, and to permit persons to whom the Software is furnished to do
 * so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 * 
 * */
 
/*
 * Created by SharpDevelop.
 * User: Kamran
 * Date: 15/01/2010
 * Time: 22:43
 * 
 * To change this template use Tools | Options | Coding | Edit Standard Headers.
 */
using System;
using System.Security.Cryptography;
using System.IO;
using System.Text;


namespace org.kamranzafar.hotfusion
{
    public enum EncryptionType
    {
    	DES,
    	RC2,
    	Rijndael,
    	TripleDES
    }

    public class Crypto
    {
    	public string InitialIV
    	{
    		get
    		{
    			return this.initialIV;
    		}
    		set
    		{
    			this.initialIV = value;
    		}
    	}
    	private string initialIV = "12345678";
    	private SymmetricAlgorithm symmetricAlgorithm;

    	public Crypto(EncryptionType Type)
    	{
    		switch (Type)
    		{
    			case EncryptionType.DES:
    				this.symmetricAlgorithm = new DESCryptoServiceProvider();
    				break;
    			case EncryptionType.RC2:
    				this.symmetricAlgorithm = new RC2CryptoServiceProvider();
    				break;
    			case EncryptionType.Rijndael:
    				this.symmetricAlgorithm = new RijndaelManaged();
    				break;
    			case EncryptionType.TripleDES:
    				this.symmetricAlgorithm = new TripleDESCryptoServiceProvider();
    				break;
    			/*case EncryptionType.RC4:
    				this.symmetricAlgorithm = new Org.Mentalis.Security.Cryptography.RC4CryptoServiceProvider();
    				break;*/
    		}
    	}

    	public Crypto(SymmetricAlgorithm ServiceProvider)
    	{
    		this.symmetricAlgorithm = ServiceProvider;
    	}

    	public string Encrypt(string Contents, string Key)
    	{
    		// use UTF8 unicode conversion for two byte characters
    		byte[] bytIn = UTF8Encoding.UTF8.GetBytes(Contents);

    		// create a MemoryStream so that the process can be done without I/O files
    		System.IO.MemoryStream ms = new System.IO.MemoryStream();

    		// set the private key
    		this.symmetricAlgorithm.Key = GetLegalKey(Key);
    		this.symmetricAlgorithm.IV = GetLegalIV();

    		// create an Encryptor from the Provider Service instance
    		ICryptoTransform encrypto = this.symmetricAlgorithm.CreateEncryptor();

    		// create Crypto Stream that transforms a stream using the encryption
    		CryptoStream cs = new CryptoStream(ms, encrypto, CryptoStreamMode.Write);

    		// write out encrypted content into MemoryStream
    		cs.Write(bytIn, 0, bytIn.Length);
    		cs.FlushFinalBlock();

    		ms.Close();
    		byte[] bytOut = ms.ToArray();

    		// convert into Base64 so that the result can be used in xml
    		return System.Convert.ToBase64String(bytOut);
    	}

    	public string Decrypt(string Contents, string Key)
    	{
    		// convert from Base64 to binary
    		byte[] bytIn = System.Convert.FromBase64String(Contents);
    		// create a MemoryStream with the input
    		System.IO.MemoryStream ms = new System.IO.MemoryStream(bytIn, 0, bytIn.Length);

    		// set the private key
    		this.symmetricAlgorithm.Key = GetLegalKey(Key);
    		this.symmetricAlgorithm.IV = GetLegalIV();

    		// create a Decryptor from the Provider Service instance
    		ICryptoTransform encrypto = this.symmetricAlgorithm.CreateDecryptor();

    		// create Crypto Stream that transforms a stream using the decryption
    		CryptoStream cs = new CryptoStream(ms, encrypto, CryptoStreamMode.Read);

    		// read out the result from the Crypto Stream
    		System.IO.StreamReader sr = new System.IO.StreamReader( cs );
    		return sr.ReadToEnd();
    	}

    	private byte[] GetLegalKey(string Key)
    	{
    		string sTemp = Key;
    		this.symmetricAlgorithm.GenerateKey();
    		byte[] bytTemp = this.symmetricAlgorithm.Key;
    		int KeyLength = bytTemp.Length;
    		if (sTemp.Length > KeyLength)
    			sTemp = sTemp.Substring(0, KeyLength);
    		else if (sTemp.Length < KeyLength)
    			sTemp = sTemp.PadRight(KeyLength, ' ');

    		return ASCIIEncoding.ASCII.GetBytes(sTemp);
    	}

    	private byte[] GetLegalIV()
    	{
    		// The initial string of IV may be modified with any data you like
    		string sTemp = this.initialIV;
    		this.symmetricAlgorithm.GenerateIV();
    		byte[] bytTemp = this.symmetricAlgorithm.IV;
    		int IVLength = bytTemp.Length;
    		if (sTemp.Length > IVLength)
    			sTemp = sTemp.Substring(0, IVLength);
    		else if (sTemp.Length < IVLength)
    			sTemp = sTemp.PadRight(IVLength, ' ');

    		return ASCIIEncoding.ASCII.GetBytes(sTemp);
    	}
    }

}
